/*
 *  Copyright (C) 2009 Takaji
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * AccountingView.java
 *
 * Created on Dec 30, 2009, 12:44:20 AM
 */
package dakside.hacc.modules.accounting.accountposting;

import dakside.hacc.core.models.AccountPeriod;
import dakside.hacc.core.models.JournalEntry;
import dakside.hacc.core.models.Transaction;
import dakside.hacc.core.models.comparators.AccountPeriodComparator;
import java.awt.Component;
import java.util.Arrays;
import org.dakside.duck.plugins.AppConstants;
import org.dakside.duck.plugins.Command;
import org.dakside.duck.plugins.DefaultCommandInvoker;
import org.dakside.duck.plugins.ToolbarContainer;
import org.dakside.utils.SystemHelper;

/**
 * Accounting view
 * @author Takaji
 */
public class AccountingView extends javax.swing.JPanel implements ToolbarContainer {

    AccountingController controller = null;

    /** Creates new form AccountingView */
    public AccountingView() {
        initComponents();
        getInvoker();
        controller = new AccountingController(this);

        refreshPostingInfo();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        transactionSelector = new javax.swing.ButtonGroup();
        accountPeriodSelector = new javax.swing.ButtonGroup();
        customToolbar = new javax.swing.JToolBar();
        jButton1 = new javax.swing.JButton();
        jPanel5 = new javax.swing.JPanel();
        btnPost = new javax.swing.JButton();
        rbSpecifiedTransaction = new javax.swing.JRadioButton();
        cboTransaction = new javax.swing.JComboBox();
        rbAllTransactions = new javax.swing.JRadioButton();
        jSeparator1 = new javax.swing.JSeparator();
        jSeparator2 = new javax.swing.JSeparator();
        rbToSpecifiedAccount = new javax.swing.JRadioButton();
        cboAccountPeriod = new javax.swing.JComboBox();
        rbToAutoMatchAccountPeriod = new javax.swing.JRadioButton();
        jScrollPane3 = new javax.swing.JScrollPane();
        txtResult = new javax.swing.JTextArea();

        customToolbar.setFloatable(false);
        customToolbar.setRollover(true);
        customToolbar.setName("customToolbar"); // NOI18N

        jButton1.setText("Auto close periods");
        jButton1.setToolTipText("Auto close all previous account periods"); // NOI18N
        jButton1.setFocusable(false);
        jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton1.setName("jButton1"); // NOI18N
        jButton1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        customToolbar.add(jButton1);

        jPanel5.setName("jPanel5"); // NOI18N

        btnPost.setText("Account Posting");
        btnPost.setName("btnPost"); // NOI18N
        btnPost.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnPostActionPerformed(evt);
            }
        });

        transactionSelector.add(rbSpecifiedTransaction);
        rbSpecifiedTransaction.setText("a specified transaction");
        rbSpecifiedTransaction.setName("rbSpecifiedTransaction"); // NOI18N
        rbSpecifiedTransaction.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbSpecifiedTransactionActionPerformed(evt);
            }
        });

        cboTransaction.setEnabled(false);
        cboTransaction.setName("cboTransaction"); // NOI18N

        transactionSelector.add(rbAllTransactions);
        rbAllTransactions.setSelected(true);
        rbAllTransactions.setText("all transactions");
        rbAllTransactions.setName("rbAllTransactions"); // NOI18N
        rbAllTransactions.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbAllTransactionsActionPerformed(evt);
            }
        });

        jSeparator1.setName("jSeparator1"); // NOI18N

        jSeparator2.setName("jSeparator2"); // NOI18N

        accountPeriodSelector.add(rbToSpecifiedAccount);
        rbToSpecifiedAccount.setText("to a specified account period");
        rbToSpecifiedAccount.setName("rbToSpecifiedAccount"); // NOI18N
        rbToSpecifiedAccount.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbToSpecifiedAccountActionPerformed(evt);
            }
        });

        cboAccountPeriod.setEnabled(false);
        cboAccountPeriod.setName("cboAccountPeriod"); // NOI18N

        accountPeriodSelector.add(rbToAutoMatchAccountPeriod);
        rbToAutoMatchAccountPeriod.setSelected(true);
        rbToAutoMatchAccountPeriod.setText("auto select account period by transaction date");
        rbToAutoMatchAccountPeriod.setName("rbToAutoMatchAccountPeriod"); // NOI18N
        rbToAutoMatchAccountPeriod.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbToAutoMatchAccountPeriodActionPerformed(evt);
            }
        });

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        txtResult.setColumns(20);
        txtResult.setEditable(false);
        txtResult.setRows(5);
        txtResult.setName("txtResult"); // NOI18N
        jScrollPane3.setViewportView(txtResult);

        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
        jPanel5.setLayout(jPanel5Layout);
        jPanel5Layout.setHorizontalGroup(
            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
                    .addComponent(rbAllTransactions, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnPost, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel5Layout.createSequentialGroup()
                        .addComponent(rbSpecifiedTransaction)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cboTransaction, 0, 311, Short.MAX_VALUE))
                    .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel5Layout.createSequentialGroup()
                        .addComponent(rbToSpecifiedAccount)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cboAccountPeriod, 0, 271, Short.MAX_VALUE))
                    .addComponent(rbToAutoMatchAccountPeriod, javax.swing.GroupLayout.Alignment.LEADING))
                .addContainerGap())
        );
        jPanel5Layout.setVerticalGroup(
            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(btnPost, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(rbSpecifiedTransaction)
                    .addComponent(cboTransaction, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(rbAllTransactions)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(rbToSpecifiedAccount)
                    .addComponent(cboAccountPeriod, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(rbToAutoMatchAccountPeriod)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 65, Short.MAX_VALUE)
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void doPost(Transaction transaction) {
        if (transaction == null) {
            println("Invalid transaction");
            return;
        }
        //TOTO this function is so slow, should we implement it as a background task?

        //get account period
        AccountPeriod period = null;
        if (rbToSpecifiedAccount.isSelected()) {
            //post to a specified account period
            //get selected period
            period = (AccountPeriod) cboAccountPeriod.getSelectedItem();
        } else {
            period = controller.findMatchAccountPeriod(transaction);
        }

        if (period == null) {
            println("Invalid period");
            return;
        } else if (period.getStatus() == AccountPeriod.CLOSED) {
            println("Cannot post transaction to a closed period.");
            return;
        }
        //do post here
        JournalEntry entry = controller.post(transaction, period);
        if (entry != null) {
            println("Posted " + transaction + " to period " + period);
        } else {
            println("Posting " + transaction + " to period " + period + " is failed.");
        }

    }

    private void btnPostActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPostActionPerformed
        println("Posting ...");

        //do dost for specified transaction

        if (rbSpecifiedTransaction.isSelected()) {
            Transaction trx = (Transaction) cboTransaction.getSelectedItem();
            doPost(trx);
        } else {
            Transaction[] transactions = controller.getUnpostedTransactions();
            println("Auto posting " + transactions.length + " transactions ...");
            for (Transaction trx : transactions) {
                doPost(trx);
            }
        }

        println("Done!");
        println("");
        refreshPostingInfo();
    }//GEN-LAST:event_btnPostActionPerformed

    private void rbSpecifiedTransactionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbSpecifiedTransactionActionPerformed
        //can select a transaction or not
        cboTransaction.setEnabled(rbSpecifiedTransaction.isSelected());
    }//GEN-LAST:event_rbSpecifiedTransactionActionPerformed

    private void rbAllTransactionsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbAllTransactionsActionPerformed
        //can select a transaction or not
        cboTransaction.setEnabled(rbSpecifiedTransaction.isSelected());
    }//GEN-LAST:event_rbAllTransactionsActionPerformed

    private void rbToSpecifiedAccountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbToSpecifiedAccountActionPerformed
        //can select period or not
        cboAccountPeriod.setEnabled(rbToSpecifiedAccount.isSelected());
    }//GEN-LAST:event_rbToSpecifiedAccountActionPerformed

    private void rbToAutoMatchAccountPeriodActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbToAutoMatchAccountPeriodActionPerformed
        //can select period or not
        cboAccountPeriod.setEnabled(rbToSpecifiedAccount.isSelected());
    }//GEN-LAST:event_rbToAutoMatchAccountPeriodActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        controller.autoClosePeriods();
    }//GEN-LAST:event_jButton1ActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup accountPeriodSelector;
    private javax.swing.JButton btnPost;
    private javax.swing.JComboBox cboAccountPeriod;
    private javax.swing.JComboBox cboTransaction;
    private javax.swing.JToolBar customToolbar;
    private javax.swing.JButton jButton1;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JRadioButton rbAllTransactions;
    private javax.swing.JRadioButton rbSpecifiedTransaction;
    private javax.swing.JRadioButton rbToAutoMatchAccountPeriod;
    private javax.swing.JRadioButton rbToSpecifiedAccount;
    private javax.swing.ButtonGroup transactionSelector;
    private javax.swing.JTextArea txtResult;
    // End of variables declaration//GEN-END:variables

    private void refreshPostingInfo() {
        //Create sample transactions
        cboAccountPeriod.removeAllItems();
        cboTransaction.removeAllItems();

        //get unposted transaction
        Transaction[] transactions = controller.getUnpostedTransactions();
        System.out.println("There are " + transactions.length + " unposted transactions.");
        for (Transaction trx : transactions) {
            cboTransaction.addItem(trx);
        }

        //get account periods information
        AccountPeriod[] periods = controller.getAllOpeningPeriods();
        //sort period list
        Arrays.sort(periods, AccountPeriodComparator.getAscInstance());
        for (AccountPeriod period : periods) {
            cboAccountPeriod.addItem(period);
            //auto select current period
            if (AccountPeriod.CURRENT.equals(period.getState())) {
                cboAccountPeriod.setSelectedItem(period);
            }
        }
    }

    private void clearLog() {
        txtResult.setText("");
    }

    private void print(String message) {
        txtResult.append(message);
    }

    private void println(String message) {
        print(message + SystemHelper.getLineSeparator());
    }
    //TOOLBAR CONTAINER SUPPORT
    private Component[] toolbar;

    public Component[] getToolbarItems() {
        if (toolbar == null) {
            toolbar = customToolbar.getComponents();
        }
        return toolbar;
    }
    private DefaultCommandInvoker myInvoker = null;

    public final synchronized DefaultCommandInvoker getInvoker() {
        if (myInvoker == null) {
            myInvoker = new DefaultCommandInvoker();
            //add support commands
            myInvoker.add(AppConstants.Commands.REFRESH, new Command() {

                public Object invoke(Object[] args) {
                    //refresh
                    refreshPostingInfo();
                    return true;
                }
            });
        }
        return myInvoker;
    }
    //END OF TOOLBAR CONTAINER SUPPORT
}
